#ifndef TYPE_DEFINE_H
#define TYPE_DEFINE_H

#include <QString>
#include <QtGlobal>
#include <QDataStream>
#include <QDebug>

#include <cstdint>
#include <vector>

#define SUCCESS 0
#define FAILED 1
#define MSGERROR 2
#define NOSUPPORT 3
#define WARNCALL 4

// 获取某位数据，startBit从0开始，startBit<=endBit
#define BITSVAULE(data, startBit, endBit) ((~(0xFFFFFFFFFFFFFFFF << (endBit - startBit + 1))) & (data >> startBit))

// 消息ID
enum MsgID : uint16_t {
    CarAsk = 0x0001, // 车辆应答
    GenAsk = 0x8001, // 通用应答
    CarHeart = 0x0002, // 车辆心跳
    CarReg = 0x0100, // 车辆注册
    CarRegAsk = 0x8100, // 车辆注册应答
    CarAuth = 0x0102, // 车辆鉴权
    CarUpload = 0x0200, // 车辆信息汇报
    CarDownPath = 0x8203, // 下发路径规划
    CarUpPath = 0x0108, // 上报当前路径规划
    CarControl = 0x8204, // 底盘控制
    AutoCheck = 0x8888, // 自检
    AutoCheckAsk = 0x0888, // 自检应答
    PathAttribute = 0x8207, // 下发路径属性（整个机场路径属性设置）
};

// 标识位	消息头	消息体	校验码	标识位

// 标识位
const uint8_t SignFlag = 0x7E;

/**
 * @brief 故障状态定义
 第一种类型的定义
 * 位	定义	说明
    0	1:高清相机通信超时或故障	标志维持至报警解除
    1	1:左/右/后侧激光雷达超时或故障	标志维持至报警解除
    2	左右前后激光雷达时间同步失败	默认0
    3	左右前后激光雷达时间与系统时间不一致	默认0
    4	1:前方毫米波雷达故障	标志维持至报警解除
    5	1: can通信超时	标志维持至报警解除
    6	1:决策规划模块故障	默认0
    7	1:感知模块故障	默认0
    8	1:预测模块故障	默认0
    9	1:控制模块异常	默认0
    10	1：定位输出不可用	标志维持至报警解除
    11	1:RTK/GPS定位结果输出误差大	标志维持至报警解除
    12	障碍物报警	默认0
 第二种类型的定义
    位	定义	说明
    0	1:RTK/GPS定位结果输出误差大	标志维持至报警解除
    1	1:高清相机通信超时或故障	标志维持至报警解除
    2	1:双目摄像头超时或故障	标志维持至报警解除
    3	1:双目摄像头被遮挡	标志维持至报警解除
    4	1:左侧激光雷达超时或故障	标志维持至报警解除
    5	1:左侧激光雷达被遮挡	标志维持至报警解除
    6	1:右侧激光雷达超时或故障	标志维持至报警解除
    7	1:右侧激光雷达被遮挡	标志维持至报警解除
    8	1:后方激光雷达超时或故障	标志维持至报警解除
    9	1:后方激光雷达被遮挡	标志维持至报警解除
    10	1:前方毫米波雷达故障	标志维持至报警解除
    11	1:轮速传感器故障	标志维持至报警解除
    12	1:车道线寻迹无法寻迹,没找到车道线目标点；	标志维持至报警解除
    13	1:点云寻迹无法寻迹，没找到点云目标点；	标志维持至报警解除
    14	1:RTK寻迹无法寻迹，没找到GPS目标点；	标志维持至报警解除
    15	1:点云地图加载失败	标志维持至报警解除
    16	1:获取GPS轨迹点失败	标志维持至报警解除
    17	1:超出电子围栏，越界停车	标志维持至报警解除
    18	1:IMU无数据或故障	标志维持至报警解除
    19	1:底盘:转向异常	标志维持至报警解除
    20	1:底盘:档位异常	标志维持至报警解除
    21	1:底盘:油门异常	标志维持至报警解除
    22	1:底盘:刹车异常	标志维持至报警解除
    23	1:底盘:温度异常	标志维持至报警解除
    24	1:底盘:速度异常	标志维持至报警解除
    25	1:NX与主控通讯异常	标志维持至报警解除
    26	1:语音播报/声光报警异常	标志维持至报警解除
 */
typedef struct {
    uint32_t arg0 : 1;
    uint32_t arg1 : 1;
    uint32_t arg2 : 1;
    uint32_t arg3 : 1;
    uint32_t arg4 : 1;
    uint32_t arg5 : 1;
    uint32_t arg6 : 1;
    uint32_t arg7 : 1;
    uint32_t arg8 : 1;
    uint32_t arg9 : 1;
    uint32_t arg10 : 1;
    uint32_t arg11 : 1;
    uint32_t arg12 : 1;
    uint32_t arg13 : 1;
    uint32_t arg14 : 1;
    uint32_t arg15 : 1;
    uint32_t arg16 : 1;
    uint32_t arg17 : 1;
    uint32_t arg18 : 1;
    uint32_t arg19 : 1;
    uint32_t arg20 : 1;
    uint32_t arg21 : 1;
    uint32_t arg22 : 1;
    uint32_t arg23 : 1;
    uint32_t arg24 : 1;
    uint32_t arg25 : 1;
    uint32_t arg26 : 1;
} FaultState;

/**
  消息头
 */
class MsgHead
{
public:
    uint16_t version {0}; // 版本号
    uint16_t msgID {0}; // 消息ID
    uint16_t msgNum; // 消息流水号
    uint32_t carID; // 车辆ID
    uint32_t reserve; // 保留字段

    friend QDataStream &operator<<(QDataStream &stream, const MsgHead &data);
    friend QDataStream &operator>>(QDataStream &stream, MsgHead &data);
    friend QDebug operator<<(QDebug debug, const MsgHead &data);
};

//--------消息体---------//
/**
  车辆应答消息体
*/
class MsgCarAskBody
{
public:
    uint16_t askNum;
    uint16_t askID;
    uint8_t result;

    friend QDataStream &operator<<(QDataStream &stream, const MsgCarAskBody &data);
    friend QDataStream &operator>>(QDataStream &stream, MsgCarAskBody &data);
    friend QDebug operator<<(QDebug debug, const MsgCarAskBody &data);
};

/**
  通用应答消息体
*/
class MsgGenAskBody
{
public:
    uint16_t askNum;
    uint16_t askID;
    uint8_t result;

    friend QDataStream &operator<<(QDataStream &stream, const MsgGenAskBody &data);
    friend QDataStream &operator>>(QDataStream &stream, MsgGenAskBody &data);
    friend QDebug operator<<(QDebug debug, const MsgGenAskBody &data);
};

/**
  底盘控制消息体
*/
class MsgCarControlBody
{
public:
    struct Cmd {
        uint32_t id {0};
        uint16_t len {0};
        union {
            int16_t value_int16;
            uint16_t value_word;
        };
    };

    std::vector<Cmd> cmds;

    friend QDataStream &operator<<(QDataStream &stream, const MsgCarControlBody &data);
    friend QDataStream &operator>>(QDataStream &stream, MsgCarControlBody &data);
    friend QDebug operator<<(QDebug debug, const MsgCarControlBody &data);
};

/**
 * @brief 车辆注册消息体
 */
typedef struct
{
    uint8_t makerID[5];
    uint8_t carType[8];
    uint8_t carID[7];
    uint8_t reserve;
    uint8_t carNum[10];
} MsgCarRegBody;

/**
 * @brief 车辆注册应答消息体
 */
typedef struct {
    uint16_t askNum;
    uint8_t result;
    QString authCode;
} MsgCarRegAskBody;

/**
 * @brief 车辆鉴权消息体
 */
class MsgCarAuthBody
{
public:
    QString authCode;

    friend QDataStream &operator<<(QDataStream &stream, const MsgCarAuthBody &data);
    friend QDataStream &operator>>(QDataStream &stream, MsgCarAuthBody &data);
    friend QDebug operator<<(QDebug debug, const MsgCarAuthBody &data);
};

/**
 * @brief 车辆基础信息
 字段	数据类型	描述及要求
车辆纬度	INT64	以度为单位的纬度值乘以10 的9次方
车辆经度	INT64	以度为单位的经度值乘以10 的9次方
海拔高度	DWORD	海拔高度，单位为毫米（mm）
方向	WORD	范围0°～360°，正北为0，顺时针 单位0.01度
寻迹方式	WORD	0：未寻迹；1：RTK；2：图像；3：点云；
图像寻迹标志位	WORD	-1:无信号,0,未使用,1:图像寻迹中
点云寻迹标志为	WORD	-1:无信号,0,未使用,1:点云寻迹中
RTK标志位	WORD	-1:无信号,0,未使用,1:GPS, 2:BD, 3:RTK-GPS 4:RTK-BD
保留	DWORD	保留
保留	DWORD	保留
保留	DWORD	保留
速度	WORD	车辆速度，0.01 m/s
电机转速	WORD	电机转速 单位rpm
绕障标志	WORD	0：未绕障；1：绕障中
档位	WORD	0：N； 1：D； 10：R
保留	WORD	保留
保留	DWORD	保留
GPS时间 	INT64	时间，UTC时间，单位毫秒
刹车	WORD	刹车量
油门	WORD	油门量
 */
class CarBaseInfo
{
public:
    qint64 jd;
    qint64 wd;
    uint32_t hb;
    uint16_t fx;
    uint16_t arg4;
    uint16_t arg5;
    uint16_t arg6;
    uint16_t arg7;
    uint32_t reserve0;
    uint32_t reserve1;
    uint32_t reserve2;
    uint16_t arg8;
    uint16_t arg9;
    uint16_t arg10;
    uint16_t arg11;
    uint16_t reserve3;
    uint32_t reserve4;
    qint64 arg12;
    uint16_t arg13;
    uint16_t arg14;

    friend QDataStream &operator<<(QDataStream &stream, const CarBaseInfo &data);
    friend QDataStream &operator>>(QDataStream &stream, CarBaseInfo &data);
    friend QDebug operator<<(QDebug debug, const CarBaseInfo &data);
};

/**
 * @brief 车辆附加信息
 字段	数据类型	描述及要求
附加信息ID	BYTE	1-255
附加信息长度	BYTE
附加信息
------------------------------
附加信息ID	长度	描述及要求
0x1B	2	剩余电量，范围0-100%
0x50	2	车辆状态信息，详见表13
0x51	2	手刹状态 0:未知 1：未拉起，2：拉起，
0x52	2	方向盘角度，0-1200。显示为-600 - +600度
0x53	2	任务状态，0未知，1任务执行中，2任务已结束，3到达管控区
0x54	2	剩余里程（m）
0x55	2	定位状态 0：无效定位   1：有效定位，有无GPS数据
0x56	2	充电状态；0：无需充电，1：充电完成，2：充电中，3：电量低，需要充电
0x57	4	故障信息,DWORD
0x58	2	车体状态 0：空闲 1：忙碌中 2：待充电 3：充电中 4：手动控制 5：故障
0x59	4	已行进路线点百分比 0-10000，精度0.01
0x60	2	当前动作，参照5.8下发路径途径点中的动作
0x61	2	当前路径途径点ID,WORD,ID从1开始，无任务或者没到第1个途经点时，
0x62	2	毫米波雷达开关，0：关：1：开
0x63	1	0：前后都没有障碍物；1前有障碍物，2后有障碍物，4左有障碍物，8右有障碍物
0x64	4	车灯控制
0x65	1	车内冷暖空调
0x66	2	车内空调温度 16~30℃
0x67	1	整车故障级别
0x68	1	行人提示器状态
0xFF：关闭提示音；
0x69	1
0x70	4
0x74	4
0x75	4	故障状态扩展,DWORD
见故障状态定义表15
-------------------------
车灯控制
左转向灯[bit0~bit1]b00:无动作 b01:开启 b11 关闭
右转向灯[bit2~bit3]b00:无动作 b01:开启 b11 关闭
昼间行车灯[bit4~bit5]b00:无动作 b01:开启 b11 关闭
警示双闪灯[bit6~bit7]b00:无动作 b01:开启 b11 关闭
示宽灯[bit8~bit9]b00:无动作 b01:开启 b11 关闭
大灯[bit10~bit11]b00:无动作 b01:开启 b11 关闭
后雾灯[bit12~bit13]b00:无动作 b01:开启 b11 关闭
左前雾灯[bit14~bit15]b00:无动作 b01:开启 b11 关闭
右前雾灯[bit16~bit17]b00:无动作 b01:开启 b11 关闭
内顶灯[bit18~bit19]b00:无动作 b01:开启 b11 关闭
----------------------------
 */
class CarSubjoinInfo
{
public:
    enum MsgID : uint8_t {
        ID0 = 0x1B,
        ID1 = 0x50,
        ID2 = 0x51,
        ID3 = 0x52,
        ID4 = 0x53,
        ID5 = 0x54,
        ID6 = 0x55,
        ID7 = 0x56,
        ID8 = 0x57,
        ID9 = 0x58,
        ID10 = 0x59,
        ID11 = 0x60,
        ID12 = 0x61,
        ID13 = 0x62,
        ID14 = 0x63,
        ID15 = 0x64,
        ID16 = 0x65,
        ID17 = 0x66,
        ID18 = 0x67,
        ID19 = 0x68,
        ID20 = 0x69,
        ID21 = 0x70,
        ID22 = 0x74,
        ID23 = 0x75,
    };
    typedef struct {
        uint8_t id;
        uint8_t length;
        union {
            uint8_t value8;
            uint16_t value16;
            uint32_t value32;
            FaultState faultState;
        };
    } SubjoItem;
    std::vector<SubjoItem> items;

    friend QDataStream &operator<<(QDataStream &stream, const CarSubjoinInfo &data);
    friend QDataStream &operator>>(QDataStream &stream, CarSubjoinInfo &data);
    friend QDebug operator<<(QDebug debug, const CarSubjoinInfo &data);
};

class CarInfoBody
{
public:
    CarBaseInfo carBaseInfo;
    CarSubjoinInfo carSubjoinInfo;

    friend QDataStream &operator<<(QDataStream &stream, const CarInfoBody &data);
    friend QDataStream &operator>>(QDataStream &stream, CarInfoBody &data);
    friend QDebug operator<<(QDebug debug, const CarInfoBody &data);
};

/**
 * @brief 消息结构
 * @note 消息头+消息体,根据消息头中的消息类型选择消息体
 */
class Msg
{
public:
    MsgHead msgHead;
    union {
        MsgGenAskBody genAskBody;
        MsgCarAskBody carAskBody;
    };
    CarInfoBody carInfoBody;
    MsgCarControlBody carControlBody;
    MsgCarAuthBody carAuthBody;

    bool isValid() { return msgHead.msgID != 0; }

    friend QDataStream &operator<<(QDataStream &stream, const Msg &data);
    friend QDataStream &operator>>(QDataStream &stream, Msg &data);
    friend QDebug operator<<(QDebug debug, const Msg &data);
};

#endif // TYPE_DEFINE_H
